using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

using RRHH.Competencias.DataAccessLayer.Generic;
using RRHH.Competencias.DataAccessLayer.SqlServerProvider;
using RRHH.Competencias.Entities;

namespace RRHH.Competencias.DataAccessLayer
{
    public class DALSqlServerReporteDinamico : IDALReporteDinamico
    {


        public DALSqlServerReporteDinamico () { }
      

        public List<ReporteTabla> GetTablas()
        {
            DALSqlServerConnection conexion = new DALSqlServerConnection();
            SqlDataReader reader = null;
            List<ReporteTabla> listado = null;
            string sql;

            sql = @"SELECT codigo, tabla, descripcion, tipo 
                    FROM ReporteDinamicoTablas";

            SqlCommand command = new SqlCommand();
            command.Connection = conexion.Conexion;
            command.CommandText = sql;

            reader = command.ExecuteReader();

            listado = new List<ReporteTabla>();

            while (reader.Read())
            {
                ReporteTabla tabla = new ReporteTabla();

                tabla.Codigo = Convert.ToInt16(reader["codigo"]);
                tabla.Tabla = reader["tabla"].ToString();
                tabla.Descripcion = reader["descripcion"].ToString();
                tabla.Tipo = Convert.ToChar(reader["tipo"]);

                listado.Add(tabla);
            }

            reader.Close();
            command.Connection.Close();

            return listado;
        }

        public ReporteTabla CompletarTablaOrigen(ReporteTabla tabla)
        {
            DALSqlServerConnection conexion = new DALSqlServerConnection();
            SqlDataReader reader = null;
            ReporteTabla objetoCompletar = null;
            string sql;

            if (tabla == null) throw new DALException("Debe indicar la tabla el cual desea completar");

            sql = @"SELECT codigo, tabla, descripcion, tipo 
                    FROM ReporteDinamicoTablas
                    WHERE codigo = @Codigo";

            SqlCommand command = new SqlCommand();
            command.Connection = conexion.Conexion;
            command.CommandText = sql;

            command.Parameters.AddWithValue("@Codigo",tabla.Codigo);

            reader = command.ExecuteReader();

            if (!reader.HasRows) return objetoCompletar;

            objetoCompletar = new ReporteTabla();
            objetoCompletar.Codigo = tabla.Codigo;

            while (reader.Read())
            {
                objetoCompletar.Tabla = reader["tabla"].ToString();
                objetoCompletar.Descripcion = reader["descripcion"].ToString();
                objetoCompletar.Tipo = Convert.ToChar(reader["tipo"]);
            }

            reader.Close();
            command.Connection.Close();

            return objetoCompletar;
        }

        public List<ReporteCampoColumna> GetColumnas(ReporteTabla tabla)
        {
            DALSqlServerConnection conexion = new DALSqlServerConnection();
            SqlDataReader reader = null;
            List<ReporteCampoColumna> listado = null;
            string sql;

            if (tabla == null) throw new DALException("Debe indicar la tabla de la cual se desean obtener las columnas");
            
            sql = @"SELECT Campo, Descripcion, Tipo, Precision  
                    FROM vstReporteDinamicoTablasCamposDescripcion  
                    WHERE Tabla = @Tabla ";

            if (tabla.Tipo == 'T') sql = sql + " AND Descripcion IS NOT NULL";

            SqlCommand command = new SqlCommand();
            command.Connection = conexion.Conexion;
            command.CommandText = sql;

            command.Parameters.AddWithValue("@Tabla",tabla.Tabla);

            reader = command.ExecuteReader();

            listado = new List<ReporteCampoColumna>();

            while (reader.Read())
            {
                ReporteCampoColumna campo = new ReporteCampoColumna();

                campo.Nombre = reader["Campo"].ToString();

                if (reader["Descripcion"] != DBNull.Value && reader["Descripcion"].ToString().Length > 0) campo.Descripcion = reader["Descripcion"].ToString();
                else campo.Descripcion = campo.Nombre;

                campo.Tipo = this.ConvertirNombreTipoCampo(reader["Tipo"].ToString());
                if (reader["Precision"] != DBNull.Value) campo.Precision = Convert.ToInt32(reader["Precision"]);

                listado.Add(campo);
            }

            reader.Close();
            command.Connection.Close();

            return listado;
        }

        private string ConvertirNombreTipoCampo(string nombre)
        { 
            switch(nombre.ToLower())
            {
                case "char":
                case "varchar":
                case "text":
                case "ntext":
                case "nchar":
                case "nvarchar":
                    return "Texto";
                case "datetime":
                case "smalldatetime":
                    return "Fecha";
                case "bit":
                    return "Booleano";
                default:
                    return "Numero";
            }
        }

        public DataTable GetResultadoConsulta(ReporteTabla tabla, List<ReporteCampoColumna> camposMostrar, List<ReporteCriterioFiltro> camposFiltro)
        {
            DALSqlServerConnection conexion = new DALSqlServerConnection();
            DataTable resultado = new DataTable("Resultado");
            SqlCommand command = new SqlCommand();
            SqlDataAdapter adaptador;
            StringBuilder consulta = new StringBuilder();

            if (tabla == null) throw new DALException("Debe indicar el origen de los datos");
            if (camposMostrar == null) throw new DALException("Debe indicar las columnas del resultado de la consulta");
            if (camposFiltro == null) throw new DALException("Debe indicar los filtros de busqueda");

            //Contruimos la consulta
            
            //SELECT
            //Si no se indican filtros, se limina el resultado de la consulta a las primeras 1000 filas
            if (camposFiltro.Count == 0) consulta.Append("SELECT TOP 1000 ");
            else consulta.Append("SELECT ");

            foreach (ReporteCampoColumna Columna in camposMostrar)
            {
                //Si esta al ultimo omitimos la coma
                if(Columna.Orden != camposMostrar.Count) consulta.Append(Columna.Nombre + ", ");
                else consulta.Append(Columna.Nombre + " ");
            }

            //FROM
            consulta.Append("FROM " + tabla.Tabla + " ");

            //WHERE
            consulta.Append("WHERE 1=1 ");

            foreach (ReporteCriterioFiltro Filtro in camposFiltro)
            {
                consulta.Append(this.TransformarCriterioFiltroASQL(Filtro) + " ");
            }

            command.Connection = conexion.Conexion;
            command.CommandText = consulta.ToString();

            adaptador = new SqlDataAdapter();
            adaptador.SelectCommand = command;

            adaptador.Fill(resultado);

            command.Connection.Close();

            return resultado;
        }

        /// <summary>
        /// Convierte un criterio de filtro a su equivalente como
        /// clausula WHERE de una consulta SQL
        /// </summary>
        /// <param name="filtro">Filtro al que se dara formato</param>
        /// <returns>Clausula WHERE formateada</returns>
        private string TransformarCriterioFiltroASQL(ReporteCriterioFiltro filtro)
        {
            StringBuilder clausula = new StringBuilder();
            
            if (filtro == null) return String.Empty;

            clausula.Append(filtro.TipoFiltro.ToUpper() + " ");
            clausula.Append(filtro.Nombre + " ");

            switch (filtro.TipoCondicion.ToUpper())
            { 
                case "LIKE":
                    if (filtro.Tipo.ToUpper() == "TEXTO") clausula.Append("LIKE '%" + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + "%' ");
                    else return String.Empty;
                    break;
                case "EQUALS":
                    if (filtro.Tipo.ToUpper() == "BOOLEANO") clausula.Append("= 1 ");
                    else if (filtro.Tipo.ToUpper() == "NUMERO") clausula.Append("= " + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + " ");
                    else clausula.Append("= '" + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + "' ");
                    break;
                case "NOTEQUALS":
                    if (filtro.Tipo.ToUpper() == "BOOLEANO") clausula.Append("= 0 ");
                    else if (filtro.Tipo.ToUpper() == "NUMERO") clausula.Append("<> " + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + " ");
                    else clausula.Append("<> '" + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + "' ");
                    break;
                case "BETWEEN":
                    if (filtro.Tipo.ToUpper() == "TEXTO" || filtro.Tipo.ToUpper() == "FECHA") clausula.Append("BETWEEN '" + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + "' AND '" + DALSqlServerFieldFormat.controlarCadena(filtro.Hasta) + "' ");
                    else if (filtro.Tipo.ToUpper() == "NUMERO") clausula.Append("BETWEEN " + DALSqlServerFieldFormat.controlarCadena(filtro.Desde) + " AND " + DALSqlServerFieldFormat.controlarCadena(filtro.Hasta) + " ");
                    else return String.Empty;
                    break;
                case "ISNOTNULL":
                    clausula.Append("IS NOT NULL ");
                    break;
                case "ISNULL":
                    clausula.Append("IS NULL");
                    break;
                default:
                    return String.Empty;
            }

            return clausula.ToString();
        }
    }
}
